#include <iostream>
#include <unistd.h>
#include <thread>
#include <functional>

// 函数包装器functional
// 普通函数
int add(const int &a, const int &b)
{
	return a + b;
}

// 类函数
class test
{
public:
	test(const std::string &name) : str(name) { std::cout << "调用构造函数" << std::endl; }
	test(const test &other) : str(other.str) { std::cout << "调用拷贝构造函数" << std::endl; }
	~test() { std::cout << "调用析构函数" << std::endl; }
	void f(int num)
	{
		while (num--)
			std::cout << str << std::endl;
	}

	void f(const std::string &name)
	{
		std::cout << str << " " << name << std::endl;
	}

	void f1(int num)
	{
		while (num--)
			std::cout << str << std::endl;
	}

private:
	std::string str;
};

void test1()
{
	// 包装普通函数
	std::function<int(const int &, const int &)> func;
	func = add;
	std::cout << "普通函数add:" << func(1, 2) << std::endl;

	// 包装lambda表达式
	std::function<void(const std::string &)> fun = [](const std::string &str)
	{ std::cout << str << std::endl; };
	std::cout << "lambda表达式:";
	fun("Hello World");

	// 包装类函数,注意使用引用或者指针来减少类的拷贝和构造
	// 对于有重载的函数，需要强制转化为指定的类型。否则无法识别
	std::function<void(test &, int)> funt = (void (test::*)(int))&test::f;
	test t("YZC");
	funt(t, 5);

	std::function<void(test &, const std::string &)> funct1 = (void (test::*)(const std::string &))&test::f;
	funct1(t, "Hello World!");
}

// 使用bind进行绑定
void test2()
{
	auto f1 = std::bind(test1);
	f1();

	// 如果有参数，需要指定参数或者使用占用符占用参数。否则会报错
	auto f2 = std::bind(add, std::placeholders::_1, std::placeholders::_2);
	std::cout << f2(1, 2) << std::endl;

	// 锁死全部参数
	auto f3 = std::bind(add, 2, 3);
	std::cout << f3() << std::endl;

	// 锁死部分参数
	auto f4 = std::bind(add, std::placeholders::_1, 134);
	std::cout << f4(1) << std::endl;

	// 绑定类函数
	test t("绑定类函数");
	auto f5 = std::bind(&test::f1, &t, std::placeholders::_1);
	f5(3);
}

void test3()
{
	auto f1 = [](int a, int b)
	{ return a + b; };
	std::cout << f1(1, 2) << std::endl;

	auto f2 = []()
	{ std::cout << "Hello World!" << std::endl; };
	f2();

	test t("YZC");
	auto f3 = [&t](int num)
	{ t.f(num); };
	f3(5);

	auto f4 = [&t](const std::string &str)
	{ t.f(str); };
	f4("Hello World!");
}

int main()
{
	// test2();
	test3();
}